package com.zc.websocket.handler;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.zc.common.constant.RedisStreamConstants;
import com.zc.common.core.redis.stream.RedisStream;
import com.zc.common.core.websocket.pojo.CmdMsg;
import com.zc.websocket.core.TextWebSocketFrameHandler;
import com.zc.websocket.dto.param.EventParam;
import com.zc.websocket.constant.WebSocketMsgEvent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import com.zc.websocket.util.MsgUtil;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

/**
 * 给客户端发送消息
 *
 * @author Athena-xiepufeng
 */
public class WebSocketService {

    private static final RedisCache redisCache = SpringUtils.getBean(RedisCache.class);

    private static final Logger log = Logger.getLogger(WebSocketService.class.getName());

    private static final RedisStream redisStream = SpringUtils.getBean(RedisStream.class);

    /**
     * 给指定客户端发送消息
     *
     * @param subscriber
     * @param content
     * @return
     */
    public static boolean postEvent(String subscriber, String content) {

        if (subscriber == null || subscriber.isEmpty()) {
            return false;
        }

        Channel channel = MsgUtil.getChannelByTokenSN(subscriber);

        if (channel == null) {
            log.warning("发布事件失败, 因为事件订阅者 channel:" + subscriber + " 不存在");
            cancelSubscription(subscriber, content);
            return false;
        }

        channel.writeAndFlush(new TextWebSocketFrame(content));

        return true;

    }

    /**
     * 群发消息
     *
     * @param content
     * @return
     */
    public static boolean postEvent(String content) {
        if (content == null || content.isEmpty()) {
            return false;
        }

        MsgUtil.channels.writeAndFlush(new TextWebSocketFrame(content));

        return true;

    }

    /**
     * 取消存在的消息订阅
     *
     * @param subscriber
     * @param content
     */
    private static void cancelSubscription(String subscriber, String content) {
        if (subscriber == null || content == null) {
            return;
        }

        if (!JSONValidator.from(content).validate()) {
            return;
        }

        Type type = new TypeToken<CmdMsg<EventParam<String>>>() {
        }.getType();

        Gson gson = new Gson();

        CmdMsg<EventParam<String>> cmdMsg;

        try {
            cmdMsg = gson.fromJson(content, type);
        } catch (Exception e) {
            return;
        }

        EventParam<String> eventParam = cmdMsg.getParams();

        if (eventParam == null) {
            return;
        }

        if (!WebSocketMsgEvent.SUB.equals(eventParam.getSubEvent())) {
            return;
        }

        LoginUser user = redisCache.getCacheObject(Constants.LOGIN_TOKEN_KEY + subscriber);

        if (user != null) {
            return;
        }

        EventParam<JsonObject> param = new EventParam<>();

        param.setSubEvent(WebSocketMsgEvent.UNSUB);
        param.setTokenSN(subscriber);
        param.setContent(new JsonObject());

        String msg = gson.toJson(param, new TypeToken<EventParam<JsonObject>>() {
        }.getType());

        redisStream.add(RedisStreamConstants.WebSocketStreamEvent.KEY, "", msg);
    }

    /**
     * @param openid             //openid
     * @param stateResult        //状态
     * @param stateFailureReason //状态原因
     * @param state              //启动/停止
     * @return
     */
    public boolean postEventOpenId(String openid, String stateResult, String stateFailureReason, String state, String deviceCode, String portId) {
        if (openid == null || openid.isEmpty()
                || stateResult == null || stateResult.isEmpty()
                || stateFailureReason == null || stateFailureReason.isEmpty()) {
            return false;
        }

        Channel channel = TextWebSocketFrameHandler.channelMap.get(openid);

        if (channel == null) {
            log.warning("发布事件失败, 因为事件订阅者 channel:" + openid + " 不存在");
            return false;
        }
        String jsonStr = JSONObject.toJSONString(new HashMap<String, String>() {{
            put("stateResult", stateResult);
            put("stateReason", stateFailureReason);
            put("state", state);
            put("deviceCode", deviceCode);
            put("portId", portId);
        }});
        //推送信息
        ChannelFuture channelFuture = channel.writeAndFlush(new TextWebSocketFrame(jsonStr));
//        //删除通道信息
//        MsgUtil.channels.remove(channel);
//        TextWebSocketFrameHandler.channelMap.remove(openid);
//        //关闭通道
//        channel.close();
        return true;

    }

}
